Frequency Response


Frequency Response

The frequency response of a linear time invariant system represents how a system attenuates and amplifies an input signal of a specific frequency. From a practical point of view, the frequency response of a system can be estimated by applying at the input of a system a signal of frequency F1, and measuring the amplitude (and phase) of the output signal. Then, a signal of frequency F2 is applied to the system, and the amplitude of the output signal is recorder. The process repeats for different frequency values. Finally, a amplitude-frequency plot can be built from the recorded values.
La respuesta en frecuencia de un sistema lineal e invariante en el tiempo representa como un sistema atenúa o amplifica una señal de entrada de una frecuencia específica. Desde un punto de vista práctico, la repuesta en frecuencia del sistema puede ser estimada aplicando a la entrada del sistema una señal de frecuencia F1, y midiendo la amplitud (y fase) de la señal de salida. Entonces, una señal de frecuencia F2 se aplica al sistema, y la amplitud de la señal de salida es almacenada. El proceso se repita para distintos valores de frecuencia. Finalmente, una gráfica de amplitud contra frecuencia se puede construir desde los valores almacenados.

Problem 1
Create a program called FreqAnalyzer to measure the frequency response of the microphone and the speakers of your computer. After creating the project, edit the stdafx.h file to enable the ADC and DAC of your computer. Be sure to select an input and output device. Also be sure that the microphone volume is adjusted accordingly.
Cree un programa llamado FreqAnalyzer para medir la respuesta en frecuencia del micrófono y las bocinas de su computadora. Después de crear el proyecto, edite el archivo stdafx.h para habilitar el ADC y el DAC de su computadora. Asegúrese de seleccionar un dispositivo de entrada y otro de salida. También asegúrese de que el volumen del micrófono este ajustado apropiadamente.

FreqAnalyzerRun1

FreqAnalyzerRun2

stdafx.h
. . .
//_________________________________________ MIDI, Audio Card DAC's and ADC's (or GDI Game for timers)
#define WIN_DAC_ADC_SUPPORT


FreqAnalyzer.h
#pragma once //______________________________________ FreqAnalyzer.h
#include "Resource.h"
#define FREQ_MIN 60.0
#define FREQ_MAX 10000.0
#define FREQ_COUNT 50
#define FREQ_DURATION 20
#define NUM_CHANNELS 1
#define SAMPLE_RATE 44100

class FreqAnalyzer: public Win::Window
{
public:
     FreqAnalyzer()
     {
     }
     ~FreqAnalyzer()
     {
     }
     void EnableGUI(bool enabled);
     const double minFreq = log10(FREQ_MIN);
     const double maxFreq = log10(FREQ_MAX);
     const double deltaFreq = (maxFreq - minFreq)/(FREQ_COUNT - 1.0);
     double frequency = 0.0;
     double angle = 0.0;
     double sum = 0.0;
     int count = 0;
     int duration = 0;
     int index = 0;
     void DisplayFrequency();
     . . .
};


FreqAnalyzer.cpp
. . .
void FreqAnalyzer::Window_Open(Win::Event& e)
{
     btStop.Enabled = false;
     //____________________________________________________________ 1. xyResponse
     xyResponse.CaptionX = L"Frequency (Hz)";
     xyResponse.CaptionY = L"Amplitude (dB)";
     xyResponse.MinX= FREQ_MIN;
     xyResponse.MaxX= FREQ_MAX;
     xyResponse.SetDivisionCountX(5);
     xyResponse.MinY= -50.0; //dB
     xyResponse.MaxY= -10.0; //dB
     xyResponse.SetLogScaleX(true);
     xyResponse.Graphs.Add(FREQ_COUNT);
     for(int i=0; i<FREQ_COUNT; i++)
     {
          xyResponse.Graphs[0][i].x = pow(10.0, minFreq + i*deltaFreq);
          xyResponse.Graphs[0][i].y = -40.0; // dB
     }
     xyResponse.Graphs[0].Color = RGB(0, 255, 0);
     xyResponse.Graphs[0].Caption = L"Frequency Response";
     xyResponse.SetColorMode(WIN_COLOR_MODE_DARK);
     xyResponse.RefreshAll();
     //____________________________________________________________ 2. ddDac (output device list)
     const int numInputDevices = ::waveOutGetNumDevs();
     WAVEOUTCAPS woc;
     const int woutsize= sizeof(WAVEOUTCAPS);
     for (int i = 0; i < numInputDevices; i++)
     {
          if (::waveOutGetDevCaps(i, &woc, woutsize) == MMSYSERR_NOERROR)
          {
               ddDac.Items.Add(woc.szPname, i);
          }
     }
     ddDac.SelectedIndex = 0;
     //____________________________________________________________ 3. ddAdc (input devide list)
     const int numOutputDevices = ::waveInGetNumDevs();
     WAVEINCAPS wic;
     const int winsize= sizeof(WAVEINCAPS);
     for (int i = 0; i < numOutputDevices; i++)
     {
          if (::waveInGetDevCaps(i, &wic, winsize) == MMSYSERR_NOERROR)
          {
               ddAdc.Items.Add(wic.szPname, i);
          }
     }
     ddAdc.SelectedIndex = 0;
}

void FreqAnalyzer::DisplayFrequency()
{
     wchar_t text[32];
     _snwprintf_s(text, 32, _TRUNCATE, L"Frequency %g Hz", frequency);
     this->Text = text;
}

void FreqAnalyzer::dacOutput_Started(Win::Event& e)
{
}

void FreqAnalyzer::dacOutput_Stopped(Win::Event& e)
{
}

void FreqAnalyzer::dacOutput_Data(Win::Event& e)
{
     PWAVEHDR pwd = (PWAVEHDR)e.lParam;
     if (index < FREQ_COUNT)
     {
          //____________________________________________________________ 1. Add a point to the graph
          duration++;
          if (duration > FREQ_DURATION)
          {
               duration = 0;
               frequency = xyResponse.Graphs[0][index].x;
               xyResponse.Graphs[0][index].y = (count == 0) ? 0.0 : sum/count;
               sum = 0.0;
               count = 0;
               xyResponse.RefreshGraphArea();
               DisplayFrequency();
               index++;
          }
          //____________________________________________________________ 2. Generate sine wave
          __int16* data = (__int16*)(pwd->lpData);
          const int bufferSize = pwd->dwBufferLength;
          const int sampleCount = bufferSize/2;
          const double delta = 2.0*M_PI*frequency/SAMPLE_RATE;
          for (int i = 0; i<sampleCount; i++)
          {
               data[i] = (int)(32767*sin(angle)+0.5);
               angle += delta;
               if (angle>2*M_PI) angle -= 2*M_PI;
          }
          pwd->dwBytesRecorded = pwd->dwBufferLength;
     }
     else //___________________________________________________________ 3. Done!
     {
          pwd->dwBytesRecorded = 0;
          dacOutput.Stop();
          adcInput.Stop();
     }
}

void FreqAnalyzer::adcInput_Started(Win::Event& e)
{
     EnableGUI(false);
}

void FreqAnalyzer::adcInput_Stopped(Win::Event& e)
{
     EnableGUI(true);
}

void FreqAnalyzer::adcInput_Data(Win::Event& e)
{
     double rms1 = 0.0, rms2 = 0.0;
     Mm::Assistant::GetRmsLevel(e.lParam, NUM_CHANNELS, 16, rms1, rms2);
     rms1 = 20.0*log10(rms1/32767.0);
     sum += rms1;
     count++;
}

void FreqAnalyzer::btStart_Click(Win::Event& e)
{
     //____________________________________________________________ 1. Variable
     const wchar_t* error = nullptr;
     LPARAM deviceID = WAVE_MAPPER;
     //____________________________________________________________ 2. Reset
     frequency = FREQ_MIN;
     angle = 0.0;
     sum = 0.0;
     count = 0;
     duration = 0;
     index = 0;
     DisplayFrequency();
     //____________________________________________________________ 3. dacOutput start
     ddDac.GetSelectedData(deviceID);
     error = dacOutput.Start((unsigned int)deviceID, SAMPLE_RATE, NUM_CHANNELS, 16, 8192, NULL);
     if (error != NULL)
     {
          this->MessageBox(error, L"Mm::Dac", MB_OK | MB_ICONERROR);
     }
     //____________________________________________________________ 4. adcInput start
     ddAdc.GetSelectedData(deviceID);
     error = adcInput.Start((unsigned int)deviceID, SAMPLE_RATE, NUM_CHANNELS, 16, 8192, NULL);
     if (error != NULL)
     {
          this->MessageBox(error, L"Mm::Adc", MB_OK | MB_ICONERROR);
     }
}

void FreqAnalyzer::EnableGUI(bool enabled)
{
     btStart.Enabled = enabled;
     btStop.Enabled = !enabled;
     ddDac.Enabled = enabled;
     ddAdc.Enabled = enabled;
     this->EnableCloseButton(enabled);
}

void FreqAnalyzer::btStop_Click(Win::Event& e)
{
     dacOutput.Stop();
     adcInput.Stop();
}


© Copyright 2000-2021 Wintempla selo. All Rights Reserved. Jul 22 2021. Home